package cn.zl.ymcc.utils;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 密码格式校验工具类
 */
public class PasswordValidator {
    
    // 默认密码策略
    private static final int DEFAULT_MIN_LENGTH = 8;
    private static final int DEFAULT_MAX_LENGTH = 20;
    private static final boolean DEFAULT_REQUIRE_UPPERCASE = true;
    private static final boolean DEFAULT_REQUIRE_LOWERCASE = true;
    private static final boolean DEFAULT_REQUIRE_NUMBER = true;
    private static final boolean DEFAULT_REQUIRE_SPECIAL_CHAR = true;
    private static final String DEFAULT_SPECIAL_CHARS = "!@#$%^&*()_+-=[]{}|;:',.<>?/~`";
    
    // 常见弱密码列表
    private static final List<String> COMMON_WEAK_PASSWORDS = Arrays.asList(
        "password", "123456", "12345678", "123456789", "admin", 
        "qwerty", "abc123", "111111", "password1", "123123"
    );
    
    /**
     * 密码校验结果类
     */
    public static class ValidationResult {
        private final boolean valid;
        private final String message;
        
        public ValidationResult(boolean valid, String message) {
            this.valid = valid;
            this.message = message;
        }
        
        public boolean isValid() {
            return valid;
        }
        
        public String getMessage() {
            return message;
        }
        
        public static ValidationResult valid() {
            return new ValidationResult(true, "密码格式正确");
        }
        
        public static ValidationResult invalid(String message) {
            return new ValidationResult(false, message);
        }
    }
    
    /**
     * 密码策略配置类
     */
    public static class PasswordPolicy {
        private int minLength = DEFAULT_MIN_LENGTH;
        private int maxLength = DEFAULT_MAX_LENGTH;
        private boolean requireUppercase = DEFAULT_REQUIRE_UPPERCASE;
        private boolean requireLowercase = DEFAULT_REQUIRE_LOWERCASE;
        private boolean requireNumber = DEFAULT_REQUIRE_NUMBER;
        private boolean requireSpecialChar = DEFAULT_REQUIRE_SPECIAL_CHAR;
        private String specialChars = DEFAULT_SPECIAL_CHARS;
        private List<String> weakPasswords = COMMON_WEAK_PASSWORDS;
        private boolean checkWeakPassword = true;
        
        // Builder 模式
        public static class Builder {
            private final PasswordPolicy policy = new PasswordPolicy();
            
            public Builder minLength(int minLength) {
                policy.minLength = minLength;
                return this;
            }
            
            public Builder maxLength(int maxLength) {
                policy.maxLength = maxLength;
                return this;
            }
            
            public Builder requireUppercase(boolean require) {
                policy.requireUppercase = require;
                return this;
            }
            
            public Builder requireLowercase(boolean require) {
                policy.requireLowercase = require;
                return this;
            }
            
            public Builder requireNumber(boolean require) {
                policy.requireNumber = require;
                return this;
            }
            
            public Builder requireSpecialChar(boolean require) {
                policy.requireSpecialChar = require;
                return this;
            }
            
            public Builder specialChars(String chars) {
                policy.specialChars = chars;
                return this;
            }
            
            public Builder weakPasswords(List<String> weakPasswords) {
                policy.weakPasswords = weakPasswords;
                return this;
            }
            
            public Builder checkWeakPassword(boolean check) {
                policy.checkWeakPassword = check;
                return this;
            }
            
            public PasswordPolicy build() {
                return policy;
            }
        }
        
        // Getters
        public int getMinLength() { return minLength; }
        public int getMaxLength() { return maxLength; }
        public boolean isRequireUppercase() { return requireUppercase; }
        public boolean isRequireLowercase() { return requireLowercase; }
        public boolean isRequireNumber() { return requireNumber; }
        public boolean isRequireSpecialChar() { return requireSpecialChar; }
        public String getSpecialChars() { return specialChars; }
        public List<String> getWeakPasswords() { return weakPasswords; }
        public boolean isCheckWeakPassword() { return checkWeakPassword; }
    }
    
    /**
     * 使用默认策略校验密码
     */
    public static ValidationResult validate(String password) {
        return validate(password, new PasswordPolicy());
    }
    
    /**
     * 使用自定义策略校验密码
     */
    public static ValidationResult validate(String password, PasswordPolicy policy) {
        if (password == null || password.trim().isEmpty()) {
            return ValidationResult.invalid("密码不能为空");
        }
        
        // 检查长度
        if (password.length() < policy.getMinLength()) {
            return ValidationResult.invalid(
                String.format("密码长度至少为 %d 位", policy.getMinLength())
            );
        }
        
        if (password.length() > policy.getMaxLength()) {
            return ValidationResult.invalid(
                String.format("密码长度不能超过 %d 位", policy.getMaxLength())
            );
        }
        
        // 检查大写字母
        if (policy.isRequireUppercase() && !Pattern.compile("[A-Z]").matcher(password).find()) {
            return ValidationResult.invalid("密码必须包含至少一个大写字母");
        }
        
        // 检查小写字母
        if (policy.isRequireLowercase() && !Pattern.compile("[a-z]").matcher(password).find()) {
            return ValidationResult.invalid("密码必须包含至少一个小写字母");
        }
        
        // 检查数字
        if (policy.isRequireNumber() && !Pattern.compile("\\d").matcher(password).find()) {
            return ValidationResult.invalid("密码必须包含至少一个数字");
        }
        
        // 检查特殊字符
        if (policy.isRequireSpecialChar()) {
            String specialCharPattern = "[" + Pattern.quote(policy.getSpecialChars()) + "]";
            if (!Pattern.compile(specialCharPattern).matcher(password).find()) {
                return ValidationResult.invalid(
                    String.format("密码必须包含至少一个特殊字符 (%s)", policy.getSpecialChars())
                );
            }
        }
        
        // 检查弱密码
        if (policy.isCheckWeakPassword() && policy.getWeakPasswords() != null) {
            String lowerPassword = password.toLowerCase();
            for (String weakPassword : policy.getWeakPasswords()) {
                if (lowerPassword.contains(weakPassword.toLowerCase())) {
                    return ValidationResult.invalid("密码过于简单，请使用更复杂的密码");
                }
            }
        }
        
        // 检查连续字符（如 "aaa", "123"）
        /*if (hasConsecutiveCharacters(password, 3)) {
            return ValidationResult.invalid("密码不能包含3个以上连续相同的字符");
        }
        */
        // 检查顺序字符（如 "abc", "123"）
       /* if (hasSequentialCharacters(password, 3)) {
            return ValidationResult.invalid("密码不能包含3个以上连续顺序的字符");
        }*/
        
        return ValidationResult.valid();
    }
    
    /**
     * 检查连续相同字符
     */
    private static boolean hasConsecutiveCharacters(String str, int maxConsecutive) {
        if (str == null || str.length() < maxConsecutive) {
            return false;
        }
        
        int count = 1;
        for (int i = 1; i < str.length(); i++) {
            if (str.charAt(i) == str.charAt(i - 1)) {
                count++;
                if (count >= maxConsecutive) {
                    return true;
                }
            } else {
                count = 1;
            }
        }
        return false;
    }
    
    /**
     * 检查顺序字符
     */
    private static boolean hasSequentialCharacters(String str, int sequenceLength) {
        if (str == null || str.length() < sequenceLength) {
            return false;
        }
        
        for (int i = 0; i <= str.length() - sequenceLength; i++) {
            String substring = str.substring(i, i + sequenceLength);
            if (isSequential(substring) || isSequential(new StringBuilder(substring).reverse().toString())) {
                return true;
            }
        }
        return false;
    }
    
    private static boolean isSequential(String str) {
        for (int i = 1; i < str.length(); i++) {
            if (str.charAt(i) - str.charAt(i - 1) != 1) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 密码强度评估
     */
    public static PasswordStrength evaluateStrength(String password) {
        if (password == null || password.length() < 4) {
            return PasswordStrength.VERY_WEAK;
        }
        
        int score = 0;
        
        // 长度评分
        if (password.length() >= 8) score += 1;
        if (password.length() >= 12) score += 1;
        if (password.length() >= 16) score += 1;
        
        // 字符种类评分
        if (Pattern.compile("[a-z]").matcher(password).find()) score += 1;
        if (Pattern.compile("[A-Z]").matcher(password).find()) score += 1;
        if (Pattern.compile("\\d").matcher(password).find()) score += 1;
        if (Pattern.compile("[^a-zA-Z0-9]").matcher(password).find()) score += 1;
        
        // 根据总分评估强度
        if (score <= 2) return PasswordStrength.WEAK;
        if (score <= 4) return PasswordStrength.MEDIUM;
        if (score <= 6) return PasswordStrength.STRONG;
        return PasswordStrength.VERY_STRONG;
    }
    
    /**
     * 密码强度枚举
     */
    public enum PasswordStrength {
        VERY_WEAK("非常弱", 0),
        WEAK("弱", 1),
        MEDIUM("中等", 2),
        STRONG("强", 3),
        VERY_STRONG("非常强", 4);
        
        private final String description;
        private final int level;
        
        PasswordStrength(String description, int level) {
            this.description = description;
            this.level = level;
        }
        
        public String getDescription() {
            return description;
        }
        
        public int getLevel() {
            return level;
        }
    }
}